package com.gitee.wsl.mathematics.geometry.d2.contour.box

import com.gitee.wsl.mathematics.geometry.d2.contour.ring.Ring2
import com.gitee.wsl.mathematics.geometry.d2.curve.CurveShape2d
import com.gitee.wsl.mathematics.geometry.d2.curve.CurveLine
import com.gitee.wsl.mathematics.vector.vec2.Vec2f


/**
 * @author ztellman
 */
class Box2 internal constructor(ax: Float, ay: Float, bx: Float, by: Float) :
    Box<Vec2f, Box2>() {
    val lx: Float
    val ly: Float
    val ux: Float
    val uy: Float
    /*fun box3(lz: Float, uz: Float): Box3 {
        return Box3(lx, ly, lz, ux, uy, uz)
    }*/

    fun width(): Float {
        return ux - lx
    }

    fun height(): Float {
        return uy - ly
    }

    constructor(a: Vec2f, b: Vec2f) : this(a.x, a.y, b.x, b.y)

    fun scale(k: Float): Box2 {
        return scale(Vec2f(k, k))
    }

    fun scale(x: Float, y: Float): Box2 {
        return scale(Vec2f(x, y))
    }

    fun translate(x: Float, y: Float): Box2 {
        return translate(Vec2f(x, y))
    }

    fun vertices(): Array<Vec2f> {
        return arrayOf(
            Vec2f(lx, ly),
            Vec2f(ux, ly),
            Vec2f(ux, uy),
            Vec2f(lx, uy)
        )
    }

    fun outline(): Ring2 {
        val cs: MutableList<CurveShape2d> = mutableListOf()
        val vs: Array<Vec2f> = vertices()
        for (i in vs.indices) {
            cs.add(CurveLine.line(vs[i], vs[(i + 1) % 4]))
        }
        return Ring2(cs)
    }

    override fun intersects(b: Box2): Boolean {
        return if (isEmpty || b.isEmpty) {
            false
        } else (b.ux >= lx
                ) and (ux >= b.lx
                ) and (b.uy >= ly
                ) and (uy >= b.ly)
    }

    override fun lower(): Vec2f {
        return Vec2f(lx, ly)
    }

    override fun upper(): Vec2f {
        return Vec2f(ux, uy)
    }

    override val isEmpty: Boolean
        get() = this === EMPTY

    override fun construct(a: Vec2f, b: Vec2f): Box2 {
        return Box2(a.x, a.y, b.x, b.y)
    }

    override fun empty(): Box2 {
        return EMPTY
    }

    companion object {
        val EMPTY =
            Box2(Vec2f(Float.NaN, Float.NaN), Vec2f(Float.NaN, Float.NaN))
    }

    init {
        if (ax < bx) {
            lx = ax
            ux = bx
        } else {
            ux = ax
            lx = bx
        }
        if (ay < by) {
            ly = ay
            uy = by
        } else {
            uy = ay
            ly = by
        }
    }
}